package game.Engine.Entity;

import game.MainController;
import game.Input.EventSound;
import game.display.Animation;
import game.display.Images;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

/** Contains all the magic types that will be displayed
 * and used throughout the game
 * 
 * @author DMEComputer
 *
 */

public class Magic extends Entity 
{

   public static enum MagicType 
   {
      AIR(0), FIRE(1), EARTH(2), WATER(3), LIGHTNING(4);
      int num;

      MagicType(int num) 
      {
         this.num = num;
      }

      int getNum() 
      {
         return num;
      }

      static MagicType getTypebyNum(int num) 
      {
         switch (num) 
         {
         case 0:
            return AIR;
         case 1:
            return FIRE;
         case 2:
            return EARTH;
         case 3:
            return WATER;
         case 4:
            return LIGHTNING;
         default:
            return AIR;
         }
      }

      MagicType getNextType() 
      {
         switch (this) 
         {
         case AIR:
            return FIRE;
         case FIRE:
            return EARTH;
         case EARTH:
            return WATER;
         case WATER:
            return LIGHTNING;
         case LIGHTNING:
            return AIR;

         }
         return AIR;
      }

      MagicType getLastType() 
      {
         switch (this) 
         {
         case AIR:
            return LIGHTNING;
         case FIRE:
            return AIR;
         case EARTH:
            return FIRE;
         case WATER:
            return EARTH;
         case LIGHTNING:
            return WATER;

         }
         return AIR;
      }
   }

   private MagicType type;
   private boolean playerSource, hasPlayed;

   /** Constructs the magic types
    * 
    * @param source where the magic originated
    * @param speed the speed the magic is cast at
    * @param dest where the magic is destined for
    * @param type the magic type
    * @param playerSource if the magic was sourced from the player
    * @param sdx the change in the speed of the magic in the x direction
    * @param sdy the change in the speed of the magic in the y direction
    */
   
   public Magic(Point2D.Double source, double speed, Point2D.Double dest,
         MagicType type, boolean playerSource, double sdx, double sdy) 
   {
      super(source.x, source.y, getImage(type));
      this.type = type;
      state = State.NORMAL;
      double deltaX = dest.x - source.x;
      double deltaY = dest.y - source.y;
      dx = speed * deltaX / source.distance(dest);
      dy = speed * deltaY / source.distance(dest);
      if (dx / sdx > 0) 
      {
         dx += sdx;
      }
      if(dy / sdy > 0) 
      {
         dy += sdy;
      }
      this.playerSource = playerSource;

   }

   /** Checks for magic collisions with the player and alien
    * 
    */
   
   private void checkForCollisions() 
   {
      if (state == State.NORMAL) 
      {
         for (Entity e : MainController.gameEngine.entities) 
         {
            if (collidesWith(e)) 
            {
               handleCollision(e);
            }
         }
      }
   }

   /** Returns the magic type
    * 
    * @return the magic type
    */
   
   public MagicType getType() 
   {
      return type;
   }

   public void handleCollision(Entity e) 
   {
      if (!((e instanceof Magic) || (e instanceof Mouse) || (e instanceof PowerUp) || (e instanceof AlienSpawn))) 
      {
         if (playerSource) 
         {
            if (!(e instanceof Player))
            {
               e.hitBy(this);
               die();
            }
         } else
         {
            if (!(e instanceof Alien)) 
            {
               e.hitBy(this);
               die();
            }
         }
      }
   }

   /** Returns true if their is a collision and false if not
    * 
    * @param t the entity
    * @return returns true if their is a collision and false if not
    */
   
   public boolean collidesWith(Entity t) 
   {
      Rectangle2D.Double us = getBoundingBox();
      Rectangle2D.Double them = t.getBoundingBox();
      Rectangle2D intersect = us.createIntersection(them);
      if (intersect.getWidth() > 0.25 && intersect.getHeight() > 0.25) 
      {
         return true;
      } else 
      {
         return false;
      }
   }

   private static Animation getImage(MagicType type2) 
   {
      switch (type2)
      {
      case FIRE:
         return Images.FIREWEAPON.image();
      case EARTH:
         return Images.EARTHWEAPON.image();
      case WATER:
         return Images.WATERWEAPON.image();
      case AIR:
         return Images.AIRWEAPON.image();
      case LIGHTNING:
         return Images.LIGHTNINGWEAPON.image();
      default:
         return Images.AIRWEAPON.image();
      }
   }
   
   public Animation getDyingImage() 
   {
      switch (type)
      {
      case FIRE:
         return Images.REDEXPLOSION.image();
      case EARTH:
         return Images.GREENEXPLOSION.image();
      case WATER:
         return Images.BLUEEXPLOSION.image();
      case AIR:
         return Images.WHITEEXPLOSION.image();
      case LIGHTNING:
         return Images.YELLOWEXPLOSION.image();
      default:
         return Images.AIRWEAPON.image();
      }
   }

   @Override
   public void update(long timeElapsed)
   {
      super.update(timeElapsed);
      move(timeElapsed);
      checkForCollisions();
      if(state == Entity.State.DYING && !hasPlayed)
      {
    	  double changeX = Math.abs(this.x-MainController.gameEngine.player.getX());
    	  double changeY = Math.abs(this.y-MainController.gameEngine.player.getY());
    	  if(changeX < 7 && changeY < 4)MainController.soundController.addEventSoundAction(EventSound.HIT);
    	  hasPlayed = true;
      }
   }
}
